#pragma once
#include<unistd.h>
#include<cstdlib>
#include<algorithm>
#include<sstream>
#include<string>
#include<unordered_map>
#include<vector>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/socket.h>
#include<sys/sendfile.h>
#include"log.hpp"
#include"Util.hpp"

using std::cout;
using std::endl;
using std::cin;
using std::string;

#define OK 200
#define NOT_FOUND 404
#define SERVER_ERROR 500
#define BAD_REQUEST 400

#define LINE_END "\r\n"

#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define HTTP_VERSION "HTTP/1.0"
#define PAGE_404 "wwwroot/404.html"

class HttpRequest //请求
{
    public:
    std::string status_line; //请求行
    std::vector<std::string> response_header;
    std::string blank;//空行
    std::string body;//正文

    //请求行解析之后的结果
    std::string method; //方法 GET/POST
    std::string URL; // url //path&args
    std::string version; // 版本

    unordered_map<std::string,std::string> header_k_val; //解析后的k val值
    int content_length = 0;//如果有正文的话,确定正文的长度

    std::string url_path; //要访问的路径
    std::string url_suffix = "text/html";// 后缀
    std::string url_args; //用来存放带参的数据
    //std::string query_string;

    bool cji = false;
};

class HttpResponse //响应
{
    public:
    std::string status_line; //请求行
    std::vector<std::string> response_header;
    std::string blank = LINE_END;//空行
    std::string body;//正文


    int status_code = OK;//http错误码
    int fd = -1;//响应的文件的文件描述符
    int size = 0;
};

class EndPoint 
{
    //读取请求,分析请求,构建响应
    //IO通信
    private:
    void RecvHttpREqueseLine() // 读取请求行
    {
        
        if(Util::ReadLien(_sock,_http_request.status_line) <= 0)
        {
            stop = true;
            return;
        }
        

        //_http_request.status_line[_http_request.status_line.size() - 1] = '\0';
        _http_request.status_line.resize(_http_request.status_line.size()-1);
        //差错处理

        LOG(INFO,_http_request.status_line);



        //_http_request.status_line[_http_request.status_line.size() - 1] = '\n';
    }
    void RecvHttpREqueseHdader() // 读取请求报头
    {
       while(!stop)
       {
            string out;
            out.clear();
            int tsize = Util::ReadLien(_sock,out);
            if(out == "\n" && tsize == 1)
            {
                _http_request.blank = out;
                //读到了空行
                LOG(INFO,"--------------------------------------------(空行)");
                break;
            }
            if(tsize <= 0)
            {
                stop = true;
                return;
            }
            // if(tsize == -1)
            // {
            //     LOG(ERROR,"对端链接关闭");
            //     exit(1);
            // }
            out.resize(out.size()-1);
            _http_request.response_header.push_back(out);
            LOG(INFO,out); //打印请求报文信息
       }
    }
    void PareseHttpRequestlien()//解析
    {
        //auto& lien = ;
        stringstream lien(_http_request.status_line); //以空格切分
        lien >> _http_request.method >> _http_request.URL >> _http_request.version;

        //版本号进行大写转换
        transform(_http_request.method.begin(),_http_request.method.end(),_http_request.method.begin(),::toupper);

        //LOG(INFO,_http_request.status_line);
        // LOG(INFO, _http_request.method);
        // LOG(INFO, _http_request.URL);
        // LOG(INFO, _http_request.version);
    }
    void PareseHttpRequestHeader()
    {
        std::string k,val;
        for(auto& s: _http_request.response_header)
        {
            k.clear();
            val.clear();
            if(Util::CutString(s,k,val,' '))
            {
                // k[k.size()-1] = '\0';
                // cout << "debug: " << k << endl;
                // cout << "debug: " << val << endl;
                
                //k: val
                _http_request.header_k_val.insert({k,val});
            }
        }
    }

    void RecvHtppReqyestBoby()
    {
        

        if(_http_request.method != "POST") return;

        auto iter = _http_request.header_k_val.find("Content-Length:");
        LOG(INFO,"读取body");
        if(iter != _http_request.header_k_val.end())
        {
            _http_request.content_length = atoi(iter->second.c_str());
            //走到这里就是需要读取正文了
            int Content_Length = _http_request.content_length;
            auto& boby = _http_request.body;
            char ch = '\0';

            cout << "Content_Length: " << Content_Length << endl;

            while(Content_Length --)
            {
                ssize_t s = recv(_sock,&ch,1,0);

                if(s <= 0) {
                    cout << "boby是: " << _http_request.body << endl;
                    stop = true;
                    return;
                }
                boby += ch;
            }
            cout << "boby是: " << _http_request.body << endl;

        }else LOG(WARNING,"没有正文数据!!!!!!!!!!!!!!!");
        
    }

    int  ProcessCgi()
    {
        //cout << "debug: cgi" << endl;

        int input[2];
        int output[2];
        string query_string_env;
        string method_env;
        _http_response.status_code = OK;

        if(pipe(input) < 0 || pipe(output) < 0)
        {
            LOG(ERROR,"pipe error!");
             _http_response.status_code = NOT_FOUND;
            return SERVER_ERROR;
        }
        int pid = fork();


        if(pid == 0)
        {
            LOG(INFO,"调用子进程");
            //子进程
            close(input[0]);
            close(output[1]);
            method_env = "METHOD=";
            method_env += _http_request.method;

            

            putenv((char*)method_env.c_str());

            if(_http_request.method == "GET")
            {
                query_string_env = "QUERY_STRING=";
                query_string_env += _http_request.url_args; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                putenv((char*)query_string_env.c_str());
                //cerr << "QUERY_STRING" << endl;
                cout << query_string_env << endl;
            }else if(_http_request.method == "POST")
            {
                string sleng = "CONTENT_LENGTH=";
                sleng += to_string(_http_request.content_length);

                putenv((char*)sleng.c_str());
            }else {
                exit(6);
            }
            //站在子进程角度
            //input[1] 写入
            //output[0] 读取
            
            //子进程只需要读0 写1就行
            //重定向一下
            cout << "执行的路径是: " << _http_request.url_path << endl;
            dup2(input[1],1);
            dup2(output[0],0);
            //重定向之后,就不能正常打印日志了,因为标准输出被关闭了

            execl(_http_request.url_path.c_str(),_http_request.url_path.c_str(),nullptr);//进行程序替换
            exit(1);
        }else if(pid > 0) //父进程
        {
            close(input[1]);
            close(output[0]);

            if(_http_request.method == "POST")
            {


                const char* start = _http_request.body.c_str();
                int total = 0;
                int size = 0;
                //cout << "post数据开始发送" << endl;
                while(total < _http_request.content_length && (size= write(output[1], start+total, _http_request.body.size()-total)) > 0)
                {
                    total += size;
                    //cout << "发送成功1次" << endl;
                }
                //cout << "post数据发送成功" << endl;
                char ch = 0;
                while(read(input[0],&ch,1) > 0)
                {
                    _http_response.body.push_back(ch);
                }
                //cout << "post数据接受成功" << endl;
                // while(true)
                // {
                //     size = send(output[1],start + total,_http_request.body.size() - total,0);
                //     if(size > 0) total += size;
                //     else break;
                // }
            }else if(_http_request.method == "GET")
            {
                char ch = 0;
                while(read(input[0],&ch,1) > 0)
                {
                    _http_response.body.push_back(ch);
                }
                _http_response.size = _http_response.body.size();
            }else {
                //error
                return NOT_FOUND;
            }
            //cout << "正文计算成功" << endl;
            int retint = 0;
            pid_t ret =  waitpid(pid,&retint,0);//阻塞式等待
            //cout << "等待成功" << endl;
            
            close(input[0]);
            close(output[1]);

            if(ret == pid)
            {
                //获取子进程的退出码 ...
                //return OK;
                if(WIFEXITED(retint))
                {
                   return OK;
                }else {
                    return SERVER_ERROR;
                }
            }
        }else {
            //error
            LOG(ERROR,"fork error!");
            return NOT_FOUND;
        }
        cout << "开始返回,准备进行构建响应并且发送" << endl;
        return OK;
    }

    int  ProcessNotCgi()
    {
        //返回静态网页
        //不仅要返回网页,还要构建http响应
        //目标网页一定存在
        //路径在这里_http_request.url_path

        /*****************************************/
        //开始构建响应
        //响应行的填充
        _http_response.fd = open(_http_request.url_path.c_str(),O_RDONLY);//以只读形式打开

        if(_http_response.fd < 0)
        {
            //打开失败
            LOG(WARNING,"请求文件打开失败");
            return NOT_FOUND;
        }
        return OK;
    }

    public:
    EndPoint(int sock)
        :_sock(sock)
    {}

    bool RecvHttpRequest() //读取解析
    {
        if(stop)return false;

        RecvHttpREqueseLine(); //读取
        if(stop)return false;

        RecvHttpREqueseHdader();

        if(stop) return false;

            PareseHttpRequestlien(); // 解析
            PareseHttpRequestHeader();


            RecvHtppReqyestBoby(); //读取正文
        
        if(stop) return false;
        
        return true;
    }

    void HandlerError(string page)
    {
        LOG(INFO,"Error send");
        //要给用户返回对应的资源
        string info = _http_request.url_path;
        info += "  非法请求 404";
        LOG(WARNING,info);// 警告但不致命
        _http_response.fd = open(page.c_str(),O_RDONLY);
        
        if(_http_response.fd > 0)
        {
            //打开成功
            struct stat st;
            stat(page.c_str(),&st);

            string cline = "Content-Type: text/html";
            cline += LINE_END;
            _http_response.response_header.push_back(cline);

            string line = "Content-Length: ";
            line += to_string(st.st_size);
            line += LINE_END;

            _http_response.response_header.push_back(cline);
            _http_response.size = st.st_size;
        }
    }
    void HandlerOK_200()
    {
        LOG(INFO,"OK send");
        //请求行已经处理完了
        //构建响应
        string cline = "Content-Type: ";
        cline += Util::map_type[_http_request.url_suffix];
        cline += LINE_END;
        _http_response.response_header.push_back(cline);

        string line = "Content-Length: ";
        if(!_http_request.cji) line += to_string(_http_response.size); //GET
        else line += to_string(_http_response.body.size()); //POST

        line += LINE_END;
        _http_response.response_header.push_back(line);
    }
    void BuildHttpResponseHelper(int code)
    {

        _http_response.status_line += HTTP_VERSION;
        _http_response.status_line += " ";
        _http_response.status_line += to_string(code);
        _http_response.status_line += " ";
        _http_response.status_line += Util::map_code_string[code];
        _http_response.status_line += LINE_END;

        switch (code)
        {
        case NOT_FOUND:
            HandlerError(PAGE_404);
            _http_request.cji = false;
            break;
        case OK:
            HandlerOK_200();
            break;
        case SERVER_ERROR:
            HandlerError(PAGE_404);
            _http_request.cji = false;
            break;
        case BAD_REQUEST:
            HandlerError(PAGE_404);
            _http_request.cji = false;
            break;
        default:
            break;
        }
        //cout << "正文计算结果是 " << _http_response.body << endl;
    }

    void BuilbHttpResponse() //构建响应
    {
        //先判断目前是否合法   目前只处理GET于POST方法
        //_http_request.url_path += WEB_ROOT;
        
        if(_http_request.method != "GET" && _http_request.method != "POST")
        {
            _http_response.status_code = 404;
           BuildHttpResponseHelper(404);
            return;
        }
        if(_http_request.method == "GET")
        {
            size_t pos = _http_request.URL.find('?');
            if(pos != string::npos)
            {
                //找到了
                Util::CutString(_http_request.URL,_http_request.url_path,_http_request.url_args,'?');
                _http_request.cji = true;//版本是GET且带数据了
                //cout << "这个请求是 GET 带参请求" << endl;
                 //cout << "找到了" << endl;
            }
            else {
                //没找到
                //cout << "这个请求是 GET 不带参请求" << endl;
                _http_request.url_path = _http_request.URL;
                //cout << "没找到" << endl;
                _http_request.url_args.clear();
            }
        }
        else if(_http_request.method == "POST"){
            //post
            //POST版本本身就自带数据
            _http_request.url_path = _http_request.URL;
            _http_request.cji = true;
        }else {
            //error
        }
        
        string _path;
        _path = _http_request.url_path;
        _http_request.url_path = WEB_ROOT;
        _http_request.url_path += _path;
        if(_http_request.url_path[_http_request.url_path.size()-1] == '/')
        {
            //请求的是index.html
            cout << "请求的是webroot" << endl;
            _http_request.url_path += HOME_PAGE;
            _http_response.status_code = 200;
            // ProcessNotCgi();
            // BuildHttpResponseHelper(200);
            // return;
        }
        struct stat st;
        if(stat(_http_request.url_path.c_str(),&st) == 0)
        {
            if(S_ISDIR(st.st_mode))
            {
                //请求的是一个目录  
                //cout << "请求的是一个目录" << endl;
                _http_request.url_path += '/';
                _http_request.url_path += HOME_PAGE;

                stat(_http_request.url_path.c_str(),&st);
            }
            else if((st.st_mode & S_IXGRP) || (st.st_mode & S_IXUSR) || (st.st_mode & S_IXOTH))
            {
                //判断目标文件是不是可执行文件
                //特殊处理
                cout << "请求的是一个可执行文件" << endl;
                _http_request.cji = true;
            }
            //有可能请求的是一个可执行程序
            _http_response.size = st.st_size;
        }
        else {
            //跳转到404
            _http_response.status_code = 404;
            BuildHttpResponseHelper(404);
            return;
        }

        //将文件的后缀分割出来
        //path里面
        size_t pos = _http_request.url_path.rfind('.');
        if(pos < _http_request.url_path.size())
        {
            _http_request.url_suffix.clear();
            //找到了
            for(int i = pos;i < _http_request.url_path.size();i ++)
            {
                _http_request.url_suffix += _http_request.url_path[i];
            }
        }else _http_request.url_suffix = ".html";//没找到


        if(_http_request.cji == true)
        {
            cout << "执行cgi方法 ...." << endl;
            _http_response.status_code = ProcessCgi(); //cgi函数 返回的是响应的code
            //他是把结果放到响应正文里面了
        }
        else{
            cout << "执行非cgi方法" << endl;
            _http_response.status_code = ProcessNotCgi();
            //走到这里,说明没有带参数,版本也肯定是GET,请求的也不是一个可执行文件
            //只需要执行一下简单的网页返回
        }
        // cout << "debug uri:" << _http_request.URL << endl;
        // cout << "debug path:" << _http_request.url_path << endl; 
        // cout << "debug args:" << _http_request.url_args << endl; 
        // if(_http_response.status_code != OK)
        // {
        //     //
        BuildHttpResponseHelper(_http_response.status_code); //状态行,响应报头也有了,响应正文也有了,空行也有了

    }
    void SendHttpResponse() // 发送响应
    {
        //send发送出错的时候继续发送会收到一个信号

        /*------------------------------------------------------------------------*/
        //
        //
        //cout << "***********************************************************************************" << endl;

        //cout << _http_response.status_line;

        send(_sock,_http_response.status_line.c_str(),_http_response.status_line.size(),0);//发送请求行
        //cout << "请求val k的长度: " << _http_response.response_header.size() << endl;
        for(auto& s : _http_response.response_header)
        {
            //添加一下空行
            //s += LINE_END;
            send(_sock,s.c_str(),s.size(),0);
            //cout << s;
        }
        send(_sock,_http_response.blank.c_str(),_http_response.blank.size(),0);
        //cout << _http_response.blank;
        if(_http_request.cji)
        {
            //cgi格式发送 ...
            int size = 0;
            int total = 0;
            const char* start = _http_response.body.c_str();

            while((total < _http_response.body.size()) && (size = send(_sock,start + size,_http_response.body.size() - total,0)) > 0)
            {
                total += size;
            }

        }else 
        {
            sendfile(_sock,_http_response.fd,nullptr,_http_response.size);
            close(_http_response.fd);
        }
        //cout << "请求正文已经发送" << endl;
        //sendfile(0,_http_response.fd,nullptr,_http_response.size);
        
        
        //cout << "***********************************************************************************" << endl;

    }

    ~EndPoint()
    {
        if(_sock >= 0) close(_sock);
    }
    private:
    int _sock;
    bool stop = false;
    //bool _cji;
    HttpRequest _http_request;
    HttpResponse _http_response;

};

class CallBack // Entrance
{
    public:
    CallBack()
    {}
    void operator()(int sock)
    {
        HandlerRequest(sock);
    }
    //#define DEBUG 1
    static void HandlerRequest(int _sock)
    {
        std::string t("开始处理请求");
        t += to_string(_sock);
        LOG(INFO,t);

        int sock = _sock;
        // cout << "get a new link ..." << endl;
        #ifdef DEBUG
        LOG(INFO,"DEBUG");
        char buff[1024];
        recv(sock,buff,sizeof(buff),0);
        //ssize_t len = r
        cout << "---------------------being------------------------" << endl;
        cout << buff << endl;
        cout << "----------------------end-------------------------" << endl;
        #else
        LOG(INFO,"开始处理请求");
        //std::string sends("nihaohaohaohao");
        //send(sock,sends.c_str(),sends.size(),0);

        EndPoint* ep = new EndPoint(sock);
        // ----------------------------------------------------- 
        bool stt = ep->RecvHttpRequest(); //读取并解析
        if(stt)
        {
            LOG(INFO,"读取数据并且解析完毕");
            ep->BuilbHttpResponse(); //构建http响应


            ep->SendHttpResponse(); // 发送http响应
        }else LOG(WARNING,"对端关闭链接");
        
        // while(true)
        // {

        // }

        delete ep;
        LOG(INFO,"处理结束");        
        #endif
        // string out;
        // int s = 1;
        // while(s > 0)
        // {
        //     string sout;
        //     s = Util::ReadLien(sock,sout);
        //     cout << sout << endl;
        //     out += sout;
        // }
        
        // close(sock);
        LOG(INFO,"处理请求结束");
        return;
    }

    // static void* HandlerRequest2(void* _sock)
    // {
    //     std::string t("开始处理请求");
    //     t += ('0' + *(int*)_sock);
    //     LOG(INFO,t);

    //     int sock = *(int*)_sock;
    //     delete (int*)_sock;
    //     // cout << "get a new link ..." << endl;
    //     #ifdef DEBUG
    //     LOG(INFO,"DEBUG");
    //     char buff[1024];
    //     recv(sock,buff,sizeof(buff),0);
    //     //ssize_t len = r
    //     cout << "---------------------being------------------------" << endl;
    //     cout << buff << endl;
    //     cout << "----------------------end-------------------------" << endl;
    //     #else
    //     LOG(INFO,"开始处理请求");
    //     //std::string sends("nihaohaohaohao");
    //     //send(sock,sends.c_str(),sends.size(),0);

    //     EndPoint* ep = new EndPoint(sock);
    //     // ----------------------------------------------------- 
    //     bool stt = ep->RecvHttpRequest(); //读取并解析
    //     if(stt)
    //     {
    //         LOG(INFO,"读取数据并且解析完毕");
    //         ep->BuilbHttpResponse(); //构建http响应


    //         ep->SendHttpResponse(); // 发送http响应
    //     }else LOG(WARNING,"对端关闭链接");
        
    //     // while(true)
    //     // {

    //     // }

    //     delete ep;
    //     LOG(INFO,"处理结束");        
    //     #endif
    //     // string out;
    //     // int s = 1;
    //     // while(s > 0)
    //     // {
    //     //     string sout;
    //     //     s = Util::ReadLien(sock,sout);
    //     //     cout << sout << endl;
    //     //     out += sout;
    //     // }
        
    //     // close(sock);
    //     LOG(INFO,"处理请求结束");
    //     return nullptr;
    // }
    ~CallBack()
    {}

};